package ixOrm

import (
	"errors"
	"fmt"
	"log"
	"os"
	"strconv"
	"time"

	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

// DefaultConfig 返回默认配置
func DefaultConfig() *Config {
	return &Config{
		Host:     "localhost",
		Port:     3306,
		Username: "root",
		Password: "",
		Database: "test",

		// 连接参数默认值
		Charset:   "utf8mb4",
		Collation: "utf8mb4_unicode_ci",
		ParseTime: true,
		Loc:       "Local",

		MaxOpenConns:    100,
		MaxIdleConns:    10,
		ConnMaxLifetime: time.Hour,

		SlowThreshold: time.Millisecond * 200,
		LogLevel:      LogLevelSilent,

		EnableCache: false,
		CacheTTL:    time.Minute * 5,
	}
}

// Validate 验证配置
func (c *Config) Validate() error {
	// 如果设置了 SqlConn，只验证必要的字段
	if c.SqlConn != "" {
		if c.SqlConn == "" {
			return errors.New("SqlConn不能为空字符串")
		}
	} else {
		// 否则验证传统的连接参数
		if c.Host == "" {
			return errors.New("host不能为空")
		}
		if c.Port <= 0 || c.Port > 65535 {
			return errors.New("端口号必须在1-65535之间")
		}
		if c.Username == "" {
			return errors.New("用户名不能为空")
		}
		if c.Database == "" {
			return errors.New("数据库名不能为空")
		}
	}

	// 验证连接池配置
	if c.MaxOpenConns <= 0 {
		return errors.New("最大打开连接数必须大于0")
	}
	if c.MaxIdleConns <= 0 {
		return errors.New("最大空闲连接数必须大于0")
	}

	// 如果启用缓存，验证Redis配置
	if c.EnableCache && c.RedisConfig != nil {
		if c.RedisConfig.Host == "" {
			return errors.New("Redis主机地址不能为空")
		}
		if c.RedisConfig.Port <= 0 || c.RedisConfig.Port > 65535 {
			return errors.New("Redis端口号必须在1-65535之间")
		}
	}

	return nil
}

// Clone 克隆配置
func (c *Config) Clone() *Config {
	clone := *c
	if c.RedisConfig != nil {
		redisClone := *c.RedisConfig
		clone.RedisConfig = &redisClone
	}
	return &clone
}

// ConfigOption 配置选项函数
type ConfigOption func(*Config)

// WithHost 设置数据库主机
func WithHost(host string) ConfigOption {
	return func(c *Config) {
		c.Host = host
	}
}

// WithPort 设置数据库端口
func WithPort(port int) ConfigOption {
	return func(c *Config) {
		c.Port = port
	}
}

// WithAuth 设置数据库认证信息
func WithAuth(username, password string) ConfigOption {
	return func(c *Config) {
		c.Username = username
		c.Password = password
	}
}

// WithDatabase 设置数据库名
func WithDatabase(database string) ConfigOption {
	return func(c *Config) {
		c.Database = database
	}
}

// WithConnectionPool 设置连接池参数
func WithConnectionPool(maxOpen, maxIdle int, maxLifetime time.Duration) ConfigOption {
	return func(c *Config) {
		c.MaxOpenConns = maxOpen
		c.MaxIdleConns = maxIdle
		c.ConnMaxLifetime = maxLifetime
	}
}

// WithCache 启用Redis缓存（默认）
func WithCache(args ...interface{}) ConfigOption {
	return func(c *Config) {
		c.EnableCache = true
		c.CacheType = CacheTypeRedis

		if len(args) == 0 {
			return
		}

		// 解析多个参数：host, port, password, database, ttl, prefix
		redisConfig := &RedisConfig{
			Prefix: "ixorm:", // 默认前缀
		}

		for i, arg := range args {
			switch i {
			case 0: // host
				if host, ok := convertToString(arg); ok {
					redisConfig.Host = host
				}
			case 1: // port
				if port, ok := convertToInt(arg); ok {
					redisConfig.Port = port
				}
			case 2: // password
				if password, ok := convertToString(arg); ok {
					redisConfig.Password = password
				}
			case 3: // database
				if database, ok := convertToInt(arg); ok {
					redisConfig.Database = database
				}
			case 4: // ttl
				if ttl, ok := arg.(time.Duration); ok {
					c.CacheTTL = ttl
					c.RedisCacheTTL = ttl
				}
			case 5: // prefix
				if prefix, ok := convertToString(arg); ok && prefix != "" {
					redisConfig.Prefix = prefix
				}
			}
		}

		c.RedisConfig = redisConfig
	}
}

// WithRedisConn 设置Redis连接字符串
func WithRedisConn(conn string, prefix ...string) ConfigOption {
	return func(c *Config) {
		c.EnableCache = true
		c.CacheType = CacheTypeRedis

		redisPrefix := "ixorm:"
		if len(prefix) > 0 && prefix[0] != "" {
			redisPrefix = prefix[0]
		}

		c.RedisConfig = &RedisConfig{
			Conn:   conn,
			Prefix: redisPrefix,
		}
	}
}

// WithMemoryCache 启用内存缓存
func WithMemoryCache(ttl ...time.Duration) ConfigOption {
	return func(c *Config) {
		c.EnableCache = true
		// 设置内存缓存TTL，但不改变CacheType（除非未设置）
		if len(ttl) > 0 {
			c.MemoryCacheTTL = ttl[0]
		}

		// 只有在CacheType未明确设置时才设置为Memory
		// 检查是否已经通过其他配置函数设置了CacheType
		if c.CacheType == 0 && c.RedisConfig == nil {
			c.CacheType = CacheTypeMemory
			if len(ttl) > 0 {
				c.CacheTTL = ttl[0]
			}
		}
	}
}

// WithMemoryCacheDebug 启用内存缓存并开启调试模式
func WithMemoryCacheDebug(ttl time.Duration, debug bool) ConfigOption {
	return func(c *Config) {
		c.EnableCache = true
		c.MemoryCacheTTL = ttl
		c.CacheDebugMode = debug

		// 只有在CacheType未明确设置时才设置为Memory
		if c.CacheType == 0 && c.RedisConfig == nil {
			c.CacheType = CacheTypeMemory
			c.CacheTTL = ttl
		}
	}
}

// WithCacheType 设置缓存类型
func WithCacheType(cacheType CacheType) ConfigOption {
	return func(c *Config) {
		c.EnableCache = true
		c.CacheType = cacheType
	}
}

// WithRedisPrefix 设置Redis缓存前缀
func WithRedisPrefix(prefix string) ConfigOption {
	return func(c *Config) {
		if c.RedisConfig == nil {
			c.RedisConfig = &RedisConfig{}
		}
		c.RedisConfig.Prefix = prefix
	}
}

// WithCacheDebugMode 设置缓存调试模式
func WithCacheDebugMode(debug bool) ConfigOption {
	return func(c *Config) {
		c.CacheDebugMode = debug
	}
}

// WithBothCaches 同时启用Redis和内存缓存，默认使用Redis
func WithBothCaches(redisArgs []interface{}, memoryTTL ...time.Duration) ConfigOption {
	return func(c *Config) {
		c.EnableCache = true
		c.CacheType = CacheTypeRedis // 默认使用Redis

		// 配置Redis缓存
		if len(redisArgs) > 0 {
			redisConfig := &RedisConfig{
				Prefix: "ixorm:", // 默认前缀
			}

			for i, arg := range redisArgs {
				switch i {
				case 0: // host
					if host, ok := convertToString(arg); ok {
						redisConfig.Host = host
					}
				case 1: // port
					if port, ok := convertToInt(arg); ok {
						redisConfig.Port = port
					}
				case 2: // password
					if password, ok := convertToString(arg); ok {
						redisConfig.Password = password
					}
				case 3: // database
					if database, ok := convertToInt(arg); ok {
						redisConfig.Database = database
					}
				case 4: // ttl
					if ttl, ok := arg.(time.Duration); ok {
						c.CacheTTL = ttl
					}
				case 5: // prefix
					if prefix, ok := convertToString(arg); ok && prefix != "" {
						redisConfig.Prefix = prefix
					}
				}
			}

			c.RedisConfig = redisConfig
		}

		// 设置内存缓存TTL（如果指定）
		if len(memoryTTL) > 0 {
			// 这里我们使用相同的TTL，实际使用中可以根据需要调整
			c.CacheTTL = memoryTTL[0]
		}
	}
}

// convertToString 转换为字符串
func convertToString(v interface{}) (string, bool) {
	switch val := v.(type) {
	case string:
		return val, true
	case int:
		return fmt.Sprintf("%d", val), true
	case int64:
		return fmt.Sprintf("%d", val), true
	default:
		if str := fmt.Sprintf("%v", val); str != "" {
			return str, true
		}
		return "", false
	}
}

// convertToInt 转换为整数
func convertToInt(v interface{}) (int, bool) {
	switch val := v.(type) {
	case int:
		return val, true
	case int64:
		return int(val), true
	case string:
		if i, err := strconv.Atoi(val); err == nil {
			return i, true
		}
		return 0, false
	default:
		return 0, false
	}
}

// WithLogLevel 设置日志级别
func WithLogLevel(level int) ConfigOption {
	return func(c *Config) {
		c.LogLevel = level
	}
}

// WithSlowThreshold 设置慢查询阈值
func WithSlowThreshold(threshold time.Duration) ConfigOption {
	return func(c *Config) {
		c.SlowThreshold = threshold
	}
}

// WithCharset 设置字符集
func WithCharset(charset string) ConfigOption {
	return func(c *Config) {
		c.Charset = charset
	}
}

// WithCollation 设置排序规则
func WithCollation(collation string) ConfigOption {
	return func(c *Config) {
		c.Collation = collation
	}
}

// WithCharsetAndCollation 同时设置字符集和排序规则
func WithCharsetAndCollation(charset, collation string) ConfigOption {
	return func(c *Config) {
		c.Charset = charset
		c.Collation = collation
	}
}

// WithParseTime 设置是否解析时间
func WithParseTime(parseTime bool) ConfigOption {
	return func(c *Config) {
		c.ParseTime = parseTime
	}
}

// WithLoc 设置时区
func WithLoc(loc string) ConfigOption {
	return func(c *Config) {
		c.Loc = loc
	}
}

// WithSqlConn 设置完整的数据库连接字符串
func WithSqlConn(sqlConn string) ConfigOption {
	return func(c *Config) {
		c.SqlConn = sqlConn
	}
}

// WithGormConfig 设置自定义GORM配置
func WithGormConfig(gormConfig *gorm.Config) ConfigOption {
	return func(c *Config) {
		c.GormConfig = gormConfig
	}
}

// WithGormLogger 设置GORM日志器
func WithGormLogger(logger logger.Interface) ConfigOption {
	return func(c *Config) {
		if c.GormConfig == nil {
			c.GormConfig = &gorm.Config{}
		}
		c.GormConfig.Logger = logger
	}
}

// WithGormNowFunc 设置GORM的时间函数
func WithGormNowFunc(nowFunc func() time.Time) ConfigOption {
	return func(c *Config) {
		if c.GormConfig == nil {
			c.GormConfig = &gorm.Config{}
		}
		c.GormConfig.NowFunc = nowFunc
	}
}

// WithGormDryRun 设置GORM干运行模式
func WithGormDryRun(dryRun bool) ConfigOption {
	return func(c *Config) {
		if c.GormConfig == nil {
			c.GormConfig = &gorm.Config{}
		}
		c.GormConfig.DryRun = dryRun
	}
}

// WithGormPrepareStmt 设置GORM预编译语句
func WithGormPrepareStmt(prepareStmt bool) ConfigOption {
	return func(c *Config) {
		if c.GormConfig == nil {
			c.GormConfig = &gorm.Config{}
		}
		c.GormConfig.PrepareStmt = prepareStmt
	}
}

// WithGormDisableAutomaticPing 禁用自动ping
func WithGormDisableAutomaticPing(disable bool) ConfigOption {
	return func(c *Config) {
		if c.GormConfig == nil {
			c.GormConfig = &gorm.Config{}
		}
		c.GormConfig.DisableAutomaticPing = disable
	}
}

// WithGormDisableForeignKeyConstraintWhenMigrating 迁移时禁用外键约束
func WithGormDisableForeignKeyConstraintWhenMigrating(disable bool) ConfigOption {
	return func(c *Config) {
		if c.GormConfig == nil {
			c.GormConfig = &gorm.Config{}
		}
		c.GormConfig.DisableForeignKeyConstraintWhenMigrating = disable
	}
}

// WithGormIgnoreRelationshipsWhenMigrating 迁移时忽略关系
func WithGormIgnoreRelationshipsWhenMigrating(ignore bool) ConfigOption {
	return func(c *Config) {
		if c.GormConfig == nil {
			c.GormConfig = &gorm.Config{}
		}
		c.GormConfig.IgnoreRelationshipsWhenMigrating = ignore
	}
}

// WithGormDisableNestedTransaction 禁用嵌套事务
func WithGormDisableNestedTransaction(disable bool) ConfigOption {
	return func(c *Config) {
		if c.GormConfig == nil {
			c.GormConfig = &gorm.Config{}
		}
		c.GormConfig.DisableNestedTransaction = disable
	}
}

// WithGormAllowGlobalUpdate 允许全局更新
func WithGormAllowGlobalUpdate(allow bool) ConfigOption {
	return func(c *Config) {
		if c.GormConfig == nil {
			c.GormConfig = &gorm.Config{}
		}
		c.GormConfig.AllowGlobalUpdate = allow
	}
}

// WithGormQueryFields 查询时包含字段
func WithGormQueryFields(queryFields bool) ConfigOption {
	return func(c *Config) {
		if c.GormConfig == nil {
			c.GormConfig = &gorm.Config{}
		}
		c.GormConfig.QueryFields = queryFields
	}
}

// WithGormCreateBatchSize 设置批量创建大小
func WithGormCreateBatchSize(batchSize int) ConfigOption {
	return func(c *Config) {
		if c.GormConfig == nil {
			c.GormConfig = &gorm.Config{}
		}
		c.GormConfig.CreateBatchSize = batchSize
	}
}

// NewDefaultGormLogger 创建默认的GORM日志器
func NewDefaultGormLogger(level logger.LogLevel, slowThreshold time.Duration) logger.Interface {
	return logger.New(
		log.New(os.Stdout, "\r\n", log.LstdFlags),
		logger.Config{
			SlowThreshold:             slowThreshold,
			LogLevel:                  level,
			IgnoreRecordNotFoundError: true,
			Colorful:                  true,
		},
	)
}

// NewSilentGormLogger 创建静默的GORM日志器
func NewSilentGormLogger() logger.Interface {
	return logger.New(
		log.New(os.Stdout, "\r\n", log.LstdFlags),
		logger.Config{
			LogLevel: logger.Silent,
		},
	)
}

// NewCustomGormLogger 创建自定义的GORM日志器
func NewCustomGormLogger(writer *log.Logger, config logger.Config) logger.Interface {
	return logger.New(writer, config)
}

// WithDebugMode 设置调试模式
func WithDebugMode(debug bool) ConfigOption {
	return func(c *Config) {
		c.DebugMode = debug
	}
}
